home *** CD-ROM | disk | FTP | other *** search
/ Die Speccy' 97 / Die Speccy' 97.iso / amiga_system / the_aminet / comm / bbs / s342q07.lha / rooma.c < prev    next >
C/C++ Source or Header  |  1995-09-12  |  26KB  |  1,040 lines

  1. /*
  2. *       rooma.c
  3. *
  4. * room code for Citadel bulletin board system.
  5. */
  6. /*
  7. *       history
  8. *
  9. * SEE THE INCREM.* FILES FOR FURTHER HISTORICAL NOTES
  10. * 84Jul12 JLS & HAW  gotoRoom() and dumpRoom() modified for <S>kip.
  11. * 84Apr04 HAW  Start 1.50a update
  12. * 83Feb24      Insert check for insufficient RAM, externs too low.
  13. * 82Dec06 CrT  2.00 release.
  14. * 82Nov05 CrT  main() splits off to become citadel.c
  15. */
  16. #include "ctdl.h"
  17. #include "math.h"
  18. #include "dos.h"
  19. /*
  20. *       Contents
  21. *
  22. * CheckForSkippedMsgs() check for skipped msgs (Mail)
  23. * CountMsgs()   counts the messages in the room.
  24. * DateSearch()    analyzes for date specs
  25. * dumpRoom()    tells us # new messages etc
  26. * fillMailRoom()    set up Mail> from log record
  27. * gotoRoom()    handles "g(oto)" command for menu
  28. * GotoNamedRoom()   goto the named room, if possible.
  29. * initCitadel()   system startup initialization
  30. * KnownRoom()   is room known?
  31. * knowRoom()    does some user know of specified room?
  32. * legalMatch()    Looks for partial matches.
  33. * listRooms()   lists known rooms
  34. * partialExist()    partial roomname matcher.
  35. * retRoom()   handle Ungoto command
  36. * roomCheck()   returns slot# of named room else ERROR
  37. * roomExists()    returns slot# of named room else ERROR
  38. * searchRooms()   searches room list for matching string
  39. * setUp()     setup the log buffer vars correctly
  40. * SkippedNewRoom()  worker function
  41. * systat()    shows current system status
  42. * tableRunner()   Applies some function to all the rooms.
  43. * UngotoMaintain()  Maintains the Ungoto list.
  44. */
  45. char        *baseRoom, BadMessages[40];
  46. int       UngotoStack[UN_STACK];
  47. char        remoteSysop = FALSE;      /* Is current user a sysop      */
  48. char        shownHidden;
  49. SListBase     Moderators =
  50.   {
  51.   NULL, ChkNtoStr, NULL, FreeNtoStr, EatNMapStr
  52.  
  53.   };
  54. int       *lPtrTab;     /* For .Ungoto    */
  55. char        BpsSet = FALSE;
  56. SListBase     BadWords =
  57.   {
  58.   NULL, FindIcky, NULL, NULL, EatIcky
  59.  
  60.   };
  61. SListBase     BadPeople =
  62.   {
  63.   NULL, FindIckyPeople, NULL, NULL, EatIckyPeople
  64.  
  65.   };
  66. extern CONFIG    cfg;   /* A buncha variables   */
  67. extern LogTable  *logTab; /* RAM index of pippuls   */
  68. extern MessageBuffer   msgBuf;
  69. extern logBuffer logBuf;  /* Pippul buffer    */
  70. extern logBuffer logTmp;  /* Pippul buffer    */
  71. extern NetBuffer netBuf;
  72. extern NetBuffer netTemp;
  73. extern struct floor     *FloorTab;
  74. extern FILE      *logfl;    /* log file descriptor    */
  75. extern FILE      *netfl;    /* Net file   */
  76. extern rTable    *roomTab;  /* RAM index of rooms   */
  77. extern aRoom     roomBuf; /* room buffer    */
  78. extern FILE      *roomfl; /* file descriptor for rooms    */
  79. extern int       thisRoom;  /* room currently in roomBuf    */
  80. extern char      loggedIn;  /* Are we logged in?    */
  81. extern char      PrintBanner;
  82. extern char      echo;    /* output flag    */
  83. extern char      prevChar;  /* Last char out    */
  84. extern char      onConsole; /* on console?    */
  85. extern char      whichIO; /* where is the I/O?    */
  86. extern int       thisSlot;  /* Current log slot   */
  87. extern char      outFlag;
  88. extern char      nextDay; /* System up before bailout?    */
  89. extern char      heldMess;
  90. extern label     oldTarget; /* Room to move messages to     */
  91. extern char      ShowNew;
  92. extern char      JustChecking;
  93. /*
  94. * DateSearch()
  95. *
  96. * This function analyzes for possible"[<|>] <date-spec>" in string.
  97. */
  98. char *DateSearch(char *str, long *before, long *after)
  99.   {
  100.   long *which;
  101.   while (*str && *str != '>' && *str != '<')
  102.   str++;
  103.   switch (*str)
  104.     {
  105.     case '>':
  106.     which = after; break;
  107.     case '<':
  108.     which = before; break;
  109.     default: return NULL;
  110.  
  111.     }
  112.   /* part of our duties is to put EOS here */
  113.   *str++ = 0;
  114.   while (*str && *str == ' ') str++;
  115.   if (*which == -1l)
  116.     {
  117.     /* if not set yet */
  118.     if (strlen(str))
  119.     ReadDate(str, which);
  120.     else
  121.     *which = logBuf.lblaston;
  122.  
  123.     }
  124.   /* now we need to find the possible location of the next date spec */
  125.   /* first, skip over current date. */
  126.   while (*str && *str != ' ' && *str != '>' && *str != '<') str++;
  127.   return str;
  128.  
  129.   }
  130. /*
  131. * dumpRoom()
  132. *
  133. * This will tell us # new messages etc.
  134. */
  135. void dumpRoom(char ShowFloor)
  136.   {
  137.   extern char HasSkipped;
  138.   int   count, newCount;
  139.   CountMsgs(&count, &newCount);
  140.   if (!loggedIn && thisRoom == MAILROOM)      /* Kludge for new users */
  141.   newCount = count = 1;     /* So they see intro.   */
  142.   if (ShowFloor)Output_Citadel_Message("FLOORN",(long)FloorTab[thisFloor].FlName,NULL,NULL);
  143.   Output_Citadel_Message("NUMMSG", count, NULL, NULL);
  144.   if (newCount > 0 && !PrintBanner)
  145.   Output_Citadel_Message("NUMNEW", newCount, NULL, NULL);
  146.   if (thisRoom == LOBBY)
  147.     {
  148.     HasSkipped = FALSE;
  149.     if (tableRunner(NSRoomHasNew, TRUE) != ERROR)
  150.     return ;
  151.     if (tableRunner(RoomHasNew, TRUE) == ERROR)
  152.     return ;
  153.     if (HasSkipped)
  154.       {
  155.       if (FloorMode)
  156.       FSkipped();
  157.       else
  158.         {
  159.         Output_Citadel_Message("SKPDRM", NULL, NULL, NULL);
  160.         ShowNew = TRUE;
  161.         JustChecking = FALSE;
  162.         tableRunner(SkippedNewRoom, TRUE);
  163.  
  164.         }
  165.  
  166.       }
  167.  
  168.     }
  169.  
  170.   }
  171. /*
  172. * CountMsgs()
  173. *
  174. * This function counts the messages in the room, total and new.
  175. */
  176. void CountMsgs(int *count, int *newCount)
  177.   {
  178.   int i;
  179.   MSG_NUMBER msgNo;
  180.   for (*newCount = *count = i = 0;
  181.   i < ((thisRoom == MAILROOM) ? MAILSLOTS : MSGSPERRM);   i++)
  182.     {
  183.     /* Msg is still in system?  Count it.   */
  184.     msgNo = roomBuf.msg[i].rbmsgNo & S_MSG_MASK;
  185.     if (msgNo >= cfg.oldest)
  186.       {
  187.       (*count)++;
  188.       /* don't boggle -- just checking against newest as of */
  189.       /* the last time we were  in this room - also against */
  190.       /* msg skip bit.            */
  191.       if ((msgNo > logBuf.lbvisit[ logBuf.lbgen[thisRoom] & CALLMASK ] &&
  192.       msgNo <= cfg.newest) || msgNo != roomBuf.msg[i].rbmsgNo)
  193.         {
  194.         (*newCount)++;
  195.  
  196.         }
  197.  
  198.       }
  199.  
  200.     }
  201.  
  202.   }
  203. /*
  204. * SkippedNewRoom()
  205. *
  206. * This is used for calls to tableRunner(), clears room's SKIP flag, if
  207. * ShowNew is TRUE it prints the room's name, else just return TRUE.
  208. */
  209. int SkippedNewRoom(int i)
  210.   {
  211.   if (roomTab[i].rtflags.SKIP == 1 && RoomHasNew(i))
  212.     {
  213.     roomTab[i].rtflags.SKIP = 0;  /* Clear. */
  214.     if (ShowNew) mPrintf(" %s ", formRoom(i, TRUE, TRUE));
  215.     if (JustChecking) return TRUE;
  216.  
  217.     }
  218.   return FALSE;
  219.  
  220.   }
  221. /*
  222. * fillMailRoom()
  223. *
  224. * This fills up the Mail room.
  225. */
  226. void fillMailRoom()
  227.   {
  228.   memcpy(roomBuf.msg, logBuf.lbMail, MAIL_BULK);
  229.   noteRoom();
  230.  
  231.   }
  232. /*
  233. * gotoRoom()
  234. *
  235. * This is the menu fn to travel to a new room.
  236. * returns TRUE if room is Lobby>, else FALSE.
  237. */
  238. int gotoRoom(char *nam, char mode)
  239.   {
  240.   int  i, foundit, roomNo, s;
  241.   int  lRoom, oldFloor;
  242.   char NewFloor = FALSE;
  243.   extern int ParanoiaCount;
  244.   lRoom = thisRoom;
  245.   if (strLen(nam) == 0)
  246.     {
  247.     foundit = FALSE;  /* leaves us in Lobby> if nothing found */
  248.     if (mode != 'S')
  249.       {
  250.       SetKnown(-1, 0, thisRoom, &logBuf);
  251.       roomTab[thisRoom].rtflags.SKIP = CheckForSkippedMsgs();
  252.  
  253.       }
  254.     if (!FloorMode)
  255.       {
  256.       for (i = 0; i<MAXROOMS  &&  !foundit; i++)
  257.         {
  258.         s = knowRoom(&logBuf, i);
  259.         if (
  260.         (s == KNOW_ROOM || s == WRITE_PRIVS ||
  261.         (s != DEAD_ROOM && aide && cfg.BoolFlags.aideSeeAll &&
  262.         (!roomTab[i].rtflags.INVITE || SomeSysop())))
  263.         &&
  264.         !roomTab[i].rtflags.SKIP
  265.         )
  266.           {
  267.           if (roomTab[i].rtlastMessage >
  268.           logBuf.lbvisit[logBuf.lbgen[i] & CALLMASK] &&
  269.           roomTab[i].rtlastMessage >= cfg.oldest)
  270.             {
  271.             if (i != thisRoom)
  272.               {
  273.               foundit  = i;
  274.  
  275.               }
  276.  
  277.             }
  278.  
  279.           }
  280.  
  281.         }
  282.       getRoom(foundit);
  283.       mPrintf("%s\n ", roomBuf.rbname);
  284.  
  285.       }
  286.     else
  287.       {
  288.       NewFloor = NewRoom();
  289.       foundit = thisRoom;
  290.  
  291.       }
  292.     UngotoMaintain(lRoom);
  293.  
  294.     }
  295.   else
  296.     {
  297.     foundit = 0;
  298.     oldFloor = thisFloor;
  299.     if ((roomNo = GotoNamedRoom(nam, mode)) == ERROR)
  300.         Output_Citadel_Message("NOROOM", (long)nam, NULL, NULL);
  301.     else
  302.       {
  303.       foundit = roomNo;
  304.       if (FloorMode) NewFloor = !(oldFloor == thisFloor);
  305.  
  306.       }
  307.  
  308.     }
  309.   setUp(FALSE);
  310.   dumpRoom(NewFloor);
  311.   /* in case recover1 gets a room back for a non-existent floor */
  312.   if (!FloorTab[roomBuf.rbFlIndex].FlInuse)
  313.   roomBuf.rbFlIndex = 0;
  314.   if (thisRoom != lRoom) ParanoiaCount = 0;
  315.   return foundit;
  316.  
  317.   }
  318. /*
  319. * GotoNamedRoom()
  320. *
  321. * This function will goto the named room, if possible.
  322. */
  323. int GotoNamedRoom(char *name, char mode)
  324.   {
  325.   int roomNo;
  326.   if ((roomNo = RealGNR(name, roomExists)) == ERROR &&
  327.   (roomNo = RealGNR(name, partialExist)) == ERROR)
  328.   return ERROR;
  329.   if (roomNo != thisRoom)
  330.     {
  331.     if (mode != 'S')
  332.       {
  333.       SetKnown(-1, 0, thisRoom, &logBuf);
  334.       roomTab[thisRoom].rtflags.SKIP = CheckForSkippedMsgs();
  335.  
  336.       }
  337.     UngotoMaintain(thisRoom);
  338.     getRoom(roomNo);
  339.     /* if may have been unknown... if so, note it:      */
  340.     if (!KnownRoom(thisRoom))
  341.       {
  342.       SetKnown(0, MAXVISIT - 1, thisRoom, &logBuf);
  343.  
  344.       }
  345.  
  346.     }
  347.   return roomNo;
  348.  
  349.   }
  350. /*
  351. * RealGNR()
  352. *
  353. * This function does the real work of checking to see if a .Goto is legal.
  354. */
  355. int RealGNR(char *nam, int (*func)(char *room))
  356.   {
  357.   int roomNo;
  358.   /* non-empty room name, so now we look for it: */
  359.   if ((roomNo = roomCheck(func, nam)) == ERROR ||
  360.   roomTab[roomNo].rtflags.INVITE && !SomeSysop() &&
  361.   roomTab[roomNo].rtgen != (logBuf.lbgen[roomNo] >> GENSHIFT) &&
  362.   abs(roomTab[roomNo].rtgen - (logBuf.lbgen[roomNo] >> GENSHIFT))
  363.   != RO_OFFSET)
  364.     {
  365.     return ERROR;
  366.  
  367.     }
  368.   else
  369.     {
  370.     return roomNo;
  371.  
  372.     }
  373.  
  374.   }
  375. /*
  376. * initCitadel()
  377. *
  378. * This initializes system, returns TRUE if system is coming up normally,
  379. * false if returning from a door call.
  380. */
  381. char initCitadel()
  382.   {
  383.   SYS_FILE    tempName;
  384.   extern char ExitToMsdos;
  385.   extern long byteRate;
  386.   extern char MeetDisabled;
  387.   extern char *READ_TEXT, *VERSION, *SysVers;
  388.   int   SysVal;
  389.   char  fromDoor;
  390.   extern SListBase Arch_base, MailForward;
  391.   extern char justLostCarrier;
  392.   extern FILE *upfd;
  393.   extern int  IckyLevel;
  394.   echo = BOTH;
  395.   if (!readSysTab(TRUE, TRUE))
  396.   exit(CRASH_EXIT);/* No system table? Tacky, tacky*/
  397.   cfg.weAre = CITADEL;
  398.   if ((SysVal = systemInit()) != 0)
  399.     {
  400.     writeSysTab();
  401.     systemShutdown(SysVal);
  402.     exit(CRASH_EXIT);
  403.  
  404.     }
  405.   Output_Citadel_Message("VERSIN",NULL,NULL,NULL);
  406.   printf("This software is Public Domain, not Commercial and not Shareware.\n\n");
  407.   printf("IF YOU PAID FOR THIS SOFTWARE, SOMEONE IS RIPPING YOU OFF.\n\n");
  408.   if (access(LOCKFILE, 0) != -1)
  409.     {
  410.     printf("Lock File found!  Do you have Citadel already up?\n");
  411.     writeSysTab();  /* Save it out just in case */
  412.     systemShutdown(0);
  413.     exit(RECURSE_EXIT);
  414.  
  415.     }
  416.   SpecialMessage("Opening files         ");
  417.   /* open message files: */
  418.   InitMsgBase();
  419.   InitEvents();
  420.   initLogBuf(&logBuf);
  421.   initLogBuf(&logTmp);
  422.   initRoomBuf(&roomBuf);
  423.   initNetBuf(&netBuf);
  424.   initNetBuf(&netTemp);
  425.   initTransfers();
  426.   ReadCitInfo();
  427.   lPtrTab = (int *) GetDynamic(MAXROOMS * sizeof (int));
  428.   strCpy(oldTarget, "Aide");
  429.   baseRoom = &cfg.codeBuf[cfg.bRoom];
  430.   setUp(TRUE);
  431.   makeSysName(tempName, "CtdlLog.SYS",  &cfg.logArea);
  432.   openFile(tempName, &logfl );
  433.   makeSysName(tempName, "CtdlRoom.SYS", &cfg.roomArea);
  434.   openFile(tempName, &roomfl);
  435.   makeSysName(tempName, "CtdlArch.SYS", &cfg.roomArea);
  436.   MakeList(&Arch_base, tempName, NULL);
  437.   /**
  438.     Icky level is the first line of Badwords, filename is second line
  439.   **/
  440.   makeSysName(tempName, "BadWords.SYS", &cfg.roomArea);
  441.   if ((upfd = safeopen(tempName, READ_TEXT)) != NULL)
  442.     {
  443.     if (GetAString(msgBuf.mbtext, MAXTEXT, upfd) != NULL)
  444.     IckyLevel = atoi(msgBuf.mbtext);
  445.     if (GetAString(msgBuf.mbtext, MAXTEXT, upfd) != NULL)
  446.     strCpy(BadMessages, msgBuf.mbtext);
  447.     MakeList(&BadWords, "", upfd);
  448.     fclose(upfd);
  449.     };
  450.   /**
  451.     Icky Stuff... BadPeople.sys
  452.   **/
  453.   makeSysName(tempName, "BadPeople.SYS", &cfg.roomArea);
  454.   if ((upfd = safeopen(tempName, READ_TEXT)) != NULL)
  455.     {
  456.     MakeList(&BadPeople, "", upfd);
  457.     fclose(upfd);
  458.     };
  459.  
  460.   makeSysName(tempName, "CtdlModr.SYS", &cfg.roomArea);
  461.   MakeList(&Moderators, tempName, NULL);
  462.   if (cfg.BoolFlags.netParticipant)
  463.     {
  464.     makeSysName(tempName, "CtdlNet.SYS", &cfg.netArea);
  465.     openFile(tempName, &netfl);
  466.     NetInit();
  467.     OpenForwarding();
  468.  
  469.     }
  470.   getRoom(LOBBY);     /* load Lobby>  */
  471.   SpecialMessage("Loading Lobby...     ");
  472.   fromDoor = BackFromDoor();
  473.   if (cfg.BoolFlags.IsDoor && !fromDoor && !BpsSet)
  474.     {
  475.     printf("This is a Door C-68K.\n");
  476.     writeSysTab();
  477.     exit(RECURSE_EXIT);
  478.  
  479.     }
  480.   /* Now open the modem up */
  481.   SpecialMessage("Modem Initialization...     ");
  482.   ModemOpen((gotCarrier() && fromDoor) || cfg.BoolFlags.IsDoor);
  483.   ExitToMsdos = !ModemSetup((fromDoor ||
  484.   cfg.BoolFlags.IsDoor) && byteRate != 0);
  485.   if (!cfg.BoolFlags.IsDoor) ExitToMsdos = FALSE;
  486.   if ((fromDoor || BpsSet) && byteRate == 0)
  487.     {
  488.     DisableModem(FALSE);
  489.     whichIO = CONSOLE;
  490.  
  491.     }
  492.   else
  493.   whichIO = MODEM;
  494.   setUp(FALSE);
  495.   #ifndef MAJOR_RELEASE
  496.   if (!MeetDisabled)
  497.     {
  498.     InitBio();
  499.  
  500.     }
  501.   #endif
  502.   if (fromDoor && byteRate != 0 && !gotCarrier())
  503.   justLostCarrier = TRUE;
  504.   /* display a banner.      */
  505.   SpecialMessage("Initialization completed....");
  506.   return (char)!fromDoor;   /* if we come back from a door, don't   */
  507.   }
  508. /*
  509. * legalMatch()
  510. *
  511. * This looks for partial matches, checks legalities.
  512. */
  513. char legalMatch(int i, label target)
  514.   {
  515.   char  Equal, *endbuf;
  516.   Equal = KnownRoom(i);
  517.   if ((roomTab[i].rtflags.INUSE == 1) &&
  518.   ((aide && cfg.BoolFlags.aideSeeAll &&
  519.   !roomTab[i].rtflags.INVITE)
  520.   || Equal))
  521.     {
  522.     endbuf = lbyte(roomTab[i].rtname);
  523.     return (char)(matchString(roomTab[i].rtname, target, endbuf) != NULL);
  524.  
  525.     }
  526.   return FALSE;
  527.  
  528.   }
  529. /*
  530. * listRooms()
  531. *
  532. * This function lists known rooms.
  533. */
  534. void listRooms(char mode)
  535.   {
  536.   extern char SelDirs, SelShared, SelPriv, SelNew, SelAnon, NotForgotten;
  537.   extern char SelRO;
  538.   shownHidden = FALSE;
  539.   switch (mode)
  540.     {
  541.     case DR_SEL:   SelDirs = TRUE; break;
  542.     case SH_SEL:   SelShared = TRUE; break;
  543.     case PR_SEL:   SelPriv = TRUE; break;
  544.     case ANON_SEL: SelAnon = TRUE; break;
  545.     case READONLY: SelRO = TRUE; break;
  546.     case INT_EXPERT:
  547.     case INT_NOVICE:
  548.     case NOT_INTRO:
  549.     SelNew = TRUE; break;
  550.     case FORGOTTEN:
  551.     NotForgotten = FALSE;
  552.     SelNew = TRUE;
  553.     break;
  554.  
  555.     }
  556.   if (FloorMode)
  557.     {
  558.     FKnown(mode);
  559.  
  560.     }
  561.   else
  562.     {
  563.     /* Else */
  564.     if (SelNew && NotForgotten)
  565.       {
  566.       Output_Citadel_Message("RMUNRD", NULL, NULL, NULL);
  567.       ShowNew = 1;
  568.  
  569.       }
  570.     else if (mode == FORGOTTEN)
  571.       {
  572.       Output_Citadel_Message("FORGRM", NULL, NULL, NULL);
  573.       ShowNew = 2;
  574.  
  575.       }
  576.     tableRunner(DispRoom, TRUE);
  577.     if (mode != INT_EXPERT && SelNew && NotForgotten)
  578.       {
  579.       Output_Citadel_Message("NOURMS", NULL, NULL, NULL);
  580.       ShowNew = FALSE;
  581.       tableRunner(DispRoom, TRUE);
  582.  
  583.       }
  584.  
  585.     }
  586.   SelDirs = SelShared = SelRO = SelPriv = SelNew = SelAnon = FALSE;
  587.   NotForgotten = TRUE;
  588.  
  589.   }
  590. /*
  591. * tableRunner()
  592. *
  593. * This applies some function to all the rooms the user might know of.
  594. *
  595. * OnlyKnown: decides if every room is subject to the function call, or only
  596. * those the current user knows of.
  597. */
  598. int tableRunner(int (*func)(int rover), char OnlyKnown)
  599.   {
  600.   int rover;
  601.   for (rover = 0; rover < MAXROOMS; rover++)
  602.     {
  603.     if (!OnlyKnown || KnownRoom(rover))
  604.     if ((*func)(rover)) return rover;
  605.  
  606.     }
  607.   return ERROR;
  608.  
  609.   }
  610. /*
  611. * KnownRoom()
  612. *
  613. * This is called by tableRunner, returns whether room is known.  External flag
  614. * NotForgotten controls if we're doing a normal Known rooms or a list of
  615. * ZForgotten rooms.
  616. */
  617. int KnownRoom(int RoomNo)
  618.   {
  619.   extern char NotForgotten;
  620.   int s;
  621.   s = knowRoom(&logBuf, RoomNo);
  622.   if (NotForgotten)
  623.     {
  624.     return (s == KNOW_ROOM || s == WRITE_PRIVS);
  625.  
  626.     }
  627.   /* now checking for Forgotten rooms -- don't show if private room! */
  628.   if (!roomTab[RoomNo].rtflags.PUBLIC) return FALSE;
  629.   return (s == FORGOTTEN_ROOM);
  630.  
  631.   }
  632. /*
  633. * knowRoom()
  634. *
  635. * This will check to see if specified user knows given room.
  636. *
  637. * Return 0 if not know room, 2 if forgot room, 3 if know room and have write
  638. * permission (r/o rooms), 1 otherwise.
  639. */
  640. char knowRoom(logBuffer *lBuf, int i)
  641.   {
  642.   int difference;
  643.   if (!roomTab[i].rtflags.INUSE) return DEAD_ROOM;
  644.   difference = abs(roomTab[i].rtgen - (lBuf->lbgen[i] >> GENSHIFT));
  645.   return (char)( ((difference == 0) ? KNOW_ROOM :
  646.   (difference == RO_OFFSET) ? WRITE_PRIVS :
  647.   ((difference == FORGET_OFFSET) ? FORGOTTEN_ROOM :
  648.   (roomTab[i].rtflags.PUBLIC) ? KNOW_ROOM : UNKNOWN_ROOM)) );
  649.  
  650.   }
  651. /*
  652. * SetKnown()
  653. *
  654. * This sets up a known-room value.
  655. */
  656. void SetKnown(int GenVal, int Index, int Room, logBuffer *lBuf)
  657.   {
  658.   int val;
  659.   switch (GenVal)
  660.     {
  661.     case -2:
  662.     val = (roomTab[Room].rtgen + (MAXGEN-1)) % MAXGEN;
  663.     break;
  664.     case -1:
  665.     val = (lBuf->lbgen[Room] >> GENSHIFT);
  666.     break;
  667.     case 0:
  668.     val = roomTab[Room].rtgen;
  669.     break;
  670.     case RO_OFFSET:
  671.     val = (roomTab[Room].rtgen + RO_OFFSET) % MAXGEN;
  672.     break;
  673.     case FORGET_OFFSET:
  674.     val = (roomTab[Room].rtgen + FORGET_OFFSET) % MAXGEN;
  675.     default:
  676.     break;
  677.  
  678.     }
  679.   lBuf->lbgen[Room] = (val << GENSHIFT) + Index;
  680.  
  681.   }
  682. /*
  683. * partialExist()
  684. *
  685. * This roams the list looking for a partial match.
  686. */
  687. int partialExist(label target)
  688.   {
  689.   int rover;
  690.   for (rover = (thisRoom + 1) % MAXROOMS; rover != thisRoom;
  691.   rover = (rover + 1) % MAXROOMS)
  692.   if (legalMatch(rover, target)) return rover;
  693.   return ERROR;
  694.  
  695.   }
  696. /*
  697. * retRoom()
  698. *
  699. * This is the menu Ungoto command.
  700. */
  701. void retRoom(char *roomName)
  702.   {
  703.   int slot, OldFloor;
  704.   OldFloor = thisFloor;
  705.   if (strLen(roomName) == 0)
  706.     {
  707.     if (UngotoStack[0] == -1)
  708.       {
  709.       Output_Citadel_Message("NORMUN", NULL, NULL, NULL);
  710.       return;
  711.  
  712.       }
  713.     getRoom(UngotoStack[0]);
  714.     mPrintf("%s\n ", roomBuf.rbname);
  715.     logBuf.lbgen[thisRoom] = lPtrTab[thisRoom];
  716.     /* Now pop that top element off the stack */
  717.     memmove(UngotoStack, UngotoStack + 1, (UN_STACK - 1) * sizeof(int));
  718.     UngotoStack[UN_STACK-1] = -1;   /* bottom of stack */
  719.  
  720.     }
  721.   else
  722.     {
  723.     if (
  724.     (slot = RealGNR(roomName, roomExists)) == ERROR &&
  725.     (slot = RealGNR(roomName, partialExist)) == ERROR
  726.     )
  727.       {
  728.       Output_Citadel_Message("NOROOM", (long)roomName, NULL, NULL);
  729.       return;
  730.  
  731.       }
  732.     UngotoMaintain(thisRoom);
  733.     getRoom(slot);
  734.     logBuf.lbgen[thisRoom] = lPtrTab[thisRoom];
  735.  
  736.     }
  737.   setUp(FALSE);
  738.   dumpRoom((char) FloorMode ? !(OldFloor == thisFloor) : FALSE);
  739.  
  740.   }
  741. /*
  742. * roomCheck()
  743. *
  744. * This returns slot# of named room else ERROR as determined by checker.
  745. */
  746. int roomCheck(int (*checker)(char *name), char *nam)
  747.   {
  748.   int roomNo;
  749.   if (
  750.   (roomNo = (*checker)(nam)) == ERROR
  751.   ||
  752.   (roomNo==AIDEROOM  &&  !aide)
  753.   ||
  754.   (roomTab[roomNo].rtflags.PUBLIC == 0 && !loggedIn)
  755.   )
  756.   return ERROR;
  757.   return roomNo;
  758.  
  759.   }
  760. /*
  761. * roomExists()
  762. *
  763. * This returns slot# of named room else ERROR.
  764. */
  765. int roomExists(char *room)
  766.   {
  767.   int i;
  768.   for (i = 0;  i < MAXROOMS;  i++)
  769.     {
  770.     if (
  771.     roomTab[i].rtflags.INUSE == 1   &&
  772.     strCmpU(room, roomTab[i].rtname) == SAMESTRING
  773.     )
  774.       {
  775.       return(i);
  776.  
  777.       }
  778.  
  779.     }
  780.   return(ERROR);
  781.  
  782.   }
  783. /*
  784. * searchRooms()
  785. *
  786. * This function searches for user string in list of rooms.
  787. */
  788. void searchRooms(char *target)
  789.   {
  790.   int   i;
  791.   Output_Citadel_Message("MATCHR", NULL, NULL, NULL);
  792.   outFlag = OUTOK;
  793.   for (i = 0; i < MAXROOMS;  i++)
  794.     {
  795.     if (legalMatch(i, target))
  796.       {
  797.       mPrintf(" %s ", formRoom(i, TRUE, TRUE));
  798.  
  799.       }
  800.  
  801.     }
  802.  
  803.   }
  804. /*
  805. * setUp()
  806. *
  807. * This does the initial setup based on who's logged on.
  808. */
  809. void setUp(char justIn)
  810.   {
  811.   int   g, i, j, ourSlot;
  812.   extern long DoorsUsed;
  813.   extern int  AnonMsgCount;
  814.   extern int  IckyCount;
  815.   echo = BOTH;  /* just in case */
  816.   if (justIn)
  817.     {
  818.     for (i = 0; i < UN_STACK; i++)
  819.     UngotoStack[i] = -1;
  820.     heldMess = FALSE;
  821.     IckyCount = 0;
  822.  
  823.     }
  824.   if (!loggedIn)
  825.     {
  826.     remoteSysop = FALSE;
  827.     prevChar  = ' ';
  828.     termWidth = cfg.InitColumns;
  829.     termLF    = TRUE;
  830.     termNulls = 5;
  831.     expert    = FALSE;
  832.     aide    = FALSE;
  833.     sendTime  = TRUE;
  834.     oldToo    = FALSE;
  835.     HalfDup   = FALSE;
  836.     FloorMode = FALSE;
  837.     DoorPriv  = FALSE;
  838.     if (justIn)
  839.       {
  840.       /* set up logBuf so everything is new...  */
  841.       AnonMsgCount = 0;
  842.       for (i = 0; i < MAXVISIT;  i++)  logBuf.lbvisit[i] = cfg.oldest-1l;
  843.       /* no mail for anonymous folks: */
  844.       roomTab[MAILROOM].rtlastMessage = cfg.newest;
  845.       for (i = 0; i < MAILSLOTS;  i++)
  846.       logBuf.lbMail[i].rbmsgNo = 0l;
  847.       logBuf.lbname[0] = 0;
  848.       for (i = 0; i < MAXROOMS;  i++)
  849.         {
  850.         if (roomTab[i].rtflags.PUBLIC)
  851.           {
  852.           /* make public rooms known: */
  853.           g       = roomTab[i].rtgen;
  854.           logBuf.lbgen[i] = (g << GENSHIFT) + (MAXVISIT-1);
  855.  
  856.           }
  857.         else
  858.           {
  859.           /* make private rooms unknown: */
  860.           g       = (roomTab[i].rtgen + (MAXGEN-1)) % MAXGEN;
  861.           logBuf.lbgen[i] = (g << GENSHIFT) + (MAXVISIT-1);
  862.  
  863.           }
  864.         lPtrTab[i]  = logBuf.lbgen[i];
  865.  
  866.         }
  867.  
  868.       }
  869.  
  870.     }
  871.   else
  872.     {
  873.     /* loggedIn: */
  874.     if (justIn)
  875.       {
  876.       DoorsUsed = 0l;
  877.       remoteSysop = FALSE;
  878.       /* set gen on all unknown rooms  --  INUSE or no: */
  879.       for (i = 0;  i < MAXROOMS;  i++)
  880.         {
  881.         j = abs(roomTab[i].rtgen - (logBuf.lbgen[i] >> GENSHIFT));
  882.         if (!roomTab[i].rtflags.PUBLIC)
  883.           {
  884.           /* it is private -- is it unknown? */
  885.           if (j != 0 && aide)
  886.             {
  887.             if (SomeSysop() || (cfg.BoolFlags.aideSeeAll &&
  888.             (!roomTab[i].rtflags.INVITE || SomeSysop())))
  889.             SetKnown(0, MAXVISIT - 1, i, &logBuf);
  890.  
  891.             }
  892.           else if ((j != 0 && j != RO_OFFSET) ||
  893.           (!aide && i == AIDEROOM)
  894.           )
  895.             {
  896.             /* yes -- set   gen = (realgen-1) % MAXGEN */
  897.             /* j = (roomTab[i].rtgen + (MAXGEN-1)) % MAXGEN; */
  898.             SetKnown(-2, MAXVISIT - 1, i, &logBuf);
  899.  
  900.             }
  901.  
  902.           }
  903.         else if ((logBuf.lbgen[i] >> GENSHIFT) != roomTab[i].rtgen)
  904.           {
  905.           /* newly created public room -- remember to visit it; */
  906.           j = roomTab[i].rtgen - (logBuf.lbgen[i] >> GENSHIFT);
  907.           if (j < 0)
  908.           g = -j;
  909.           else
  910.           g = j;
  911.           if (g != FORGET_OFFSET && g != RO_OFFSET)
  912.             {
  913.             SetKnown(0, 1, i, &logBuf);
  914.  
  915.             }
  916.  
  917.           }
  918.  
  919.         }
  920.       /* special kludge for Mail> room, to signal new mail:   */
  921.       roomTab[MAILROOM].rtlastMessage = 0l;
  922.       for (i = 0;  i < MAILSLOTS;  i++)
  923.       if ((logBuf.lbMail[i].rbmsgNo & (~S_MSG_MASK)) &&
  924.       (logBuf.lbMail[i].rbmsgNo & S_MSG_MASK) > cfg.oldest)
  925.       roomTab[MAILROOM].rtlastMessage = S_MSG_MASK;
  926.       if (roomTab[MAILROOM].rtlastMessage != S_MSG_MASK)
  927.       roomTab[MAILROOM].rtlastMessage =
  928.       (logBuf.lbMail[MAILSLOTS-1].rbmsgNo & S_MSG_MASK);
  929.       /* slide lbvisit array down and change lbgen entries to match: */
  930.       for (i = (MAXVISIT - 2);  i;  i--)
  931.         {
  932.         logBuf.lbvisit[i] = logBuf.lbvisit[i-1];
  933.  
  934.         }
  935.       logBuf.lbvisit[(MAXVISIT - 1)]    = cfg.oldest;
  936.       for (i = 0;  i < MAXROOMS;  i++)
  937.         {
  938.         if ((logBuf.lbgen[i] & CALLMASK)  <  (MAXVISIT-2))
  939.           {
  940.           logBuf.lbgen[i]++;
  941.  
  942.           }
  943.         lPtrTab[i]  = logBuf.lbgen[i];
  944.  
  945.         }
  946.       /* Slide entry to top of log table: */
  947.       ourSlot = logTab[thisSlot].ltlogSlot;
  948.       slideLTab(0, thisSlot);
  949.       logTab[0].ltpwhash      = hash(logBuf.lbpw);
  950.       logTab[0].ltnmhash      = hash(logBuf.lbname);
  951.       logTab[0].ltlogSlot     = ourSlot;
  952.       logTab[0].ltnewest      = cfg.newest;
  953.  
  954.       }
  955.  
  956.     }
  957.   logBuf.lbvisit[0]   = cfg.newest;
  958.   onConsole   = (whichIO == CONSOLE);
  959.   if (thisRoom == MAILROOM)   fillMailRoom();
  960.  
  961.   }
  962. /*
  963. * CheckForSkippedMsgs()
  964. *
  965. * This function does a check for skipped msgs (Mail).
  966. */
  967. char CheckForSkippedMsgs()
  968.   {
  969.   int i;
  970.   for (i = 0;  i < ((thisRoom == MAILROOM) ? MAILSLOTS : MSGSPERRM);  i++)
  971.   if ((roomBuf.msg[i].rbmsgNo & (~S_MSG_MASK)) &&
  972.   (roomBuf.msg[i].rbmsgNo & S_MSG_MASK) >= cfg.oldest)
  973.     {
  974.     roomTab[thisRoom].rtlastMessage = S_MSG_MASK;
  975.     return TRUE;
  976.  
  977.     }
  978.   noteRoom();   /* just in case */
  979.   return FALSE;
  980.  
  981.   }
  982. /*
  983. * systat()
  984. *
  985. * This function prints out current system status (.rs).
  986. */
  987. void systat()
  988.   {
  989.   extern char *VERSION, *SysVers;
  990.   int   i;
  991.   extern long total_char_in, total_char_out;
  992.   char  buffer[15];
  993.   MSG_NUMBER  average, work;
  994.   int   roomCount;
  995.   for (roomCount = i = 0; i < MAXROOMS; i++)if (roomTab[i].rtflags.INUSE) roomCount++;
  996.   Output_Citadel_Message("NODETL", NULL, NULL, NULL);
  997.   Output_Citadel_Message("DTSTMP",NULL, NULL, NULL );
  998.   if (loggedIn)
  999.     {
  1000.     Output_Citadel_Message("WELCOM", NULL, NULL, NULL);
  1001.     if (logBuf.lbflags.NET_PRIVS)
  1002.       {
  1003.       Output_Citadel_Message("NETCRD", (long)logBuf.credit, NULL, NULL);
  1004.       };
  1005.     mPrintf("\n ");
  1006.  
  1007.     };
  1008.   Output_Citadel_Message("MSGSNO"
  1009.   ,(long) PrintPretty(cfg.newest-cfg.oldest+1, buffer)
  1010.   ,(long) PrintPretty(cfg.newest, buffer)
  1011.   ,(long) cfg.maxMSector / (1024 / MSG_SECT_SIZE)  );
  1012.   Output_Citadel_Message("LOGSLR",(long)cfg.MAXLOGTAB, MAXROOMS, roomCount);
  1013.   Output_Citadel_Message("NETDAT",total_char_in, total_char_out, NULL);
  1014.   if (cfg.oldest > 1)
  1015.   work = cfg.maxMSector;
  1016.   else
  1017.   work = cfg.catSector;
  1018.   work *= MSG_SECT_SIZE;
  1019.   if (cfg.oldest > 1)
  1020.   average = (work) / (cfg.newest - cfg.oldest + 1);
  1021.   else
  1022.   average = (work) / (cfg.newest);
  1023.  
  1024.   Output_Citadel_Message("AVERML",average, NULL, NULL);
  1025.   Output_Citadel_Message("CCPRIV",NULL, NULL, NULL);
  1026.   }
  1027. /*
  1028. * UngotoMaintain()
  1029. *
  1030. * This function maintains the Ungoto list.
  1031. */
  1032. void UngotoMaintain(int lRoom)
  1033.   {
  1034.   /* Move stack down 1 element */
  1035.   memmove(UngotoStack + 1, UngotoStack, (UN_STACK - 1) * sizeof(int));
  1036.   /* Add new element */
  1037.   UngotoStack[0] = lRoom;
  1038.  
  1039.   }
  1040.